import java.util.Base64
import java.util.ArrayList
import java.util.Arrays
import java.util.HashMap
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder

// 声明服务枚举
List<String> serverArray = new ArrayList()
serverArray.add("roc")
serverArray.add("payment")
serverArray.add("octopus")
serverArray.add("coral")
serverArray.add("mermaid")
serverArray.add("beluga")
serverArray.add("starfish")
serverArray.add("volador")
serverArray.add("riverbed")
serverArray.add("xxl-job")
serverArray.add("shark")
serverArray.add("elephant")
serverArray.add("Backend-max-amoeba")
serverArray.add("kun")
serverArray.add("kun-sandbox")


// 集成服务 serverName 定制化
List<String> serverIntegrationArray = new ArrayList()
serverIntegrationArray.add("developmentPlatform")
serverIntegrationArray.add("supportService")
serverIntegrationArray.add("runtime")
serverIntegrationArray.add("business")

// 研发服务与测试 View 映射
def serviceViewMap() {
    Map<String, String> devTestServerMap = new HashMap()
    devTestServerMap.put("roc", "MAX")
    devTestServerMap.put("octopus", "MAX")
    devTestServerMap.put("beluga", "MAX")
    devTestServerMap.put("coral", "MAX")
    devTestServerMap.put("mermaid", "MAX")
    devTestServerMap.put("kun", "KUN")
    devTestServerMap.put("kun-sandbox", "KUN")
    devTestServerMap.put("elephant", "MAX")
    devTestServerMap.put("payment", "MAX")
    devTestServerMap.put("shark", "MAX")
    devTestServerMap.put("Backend-max-amoeba", "MAX")
    return devTestServerMap
}

// 研发服务与测试 Job 名映射
def serviceJobMap(env, region) {
    Map<String, String> devTestJobMap = new HashMap()
    devTestJobMap.put("roc", "max${region.toUpperCase()}-roc-scenario" + env)
    devTestJobMap.put("octopus", "max${region.toUpperCase()}-roc-scenario" + env)
    devTestJobMap.put("beluga", "max${region.toUpperCase()}-beluga-scenario" + env)
    devTestJobMap.put("coral", "max${region.toUpperCase()}-coral-scenario" + env)
    devTestJobMap.put("mermaid", "max${region.toUpperCase()}-mermaid-scenario" + env)
    devTestJobMap.put("kun", "max${region.toUpperCase()}-kun-scenario" + env)
    devTestJobMap.put("kun-sandbox", "max${region.toUpperCase()}-kunSandbox-scenario" + env)
    devTestJobMap.put("elephant", "max${region.toUpperCase()}-elephant-scenario" + env)
    devTestJobMap.put("payment", "max${region.toUpperCase()}-payment-scenario" + env)
    devTestJobMap.put("shark", "max${region.toUpperCase()}-shark-scenario" + env)
    devTestJobMap.put("Backend-max-amoeba", "max${region.toUpperCase()}-amoeba-scenario" + env)
    return devTestJobMap
}

// 集成服务配置
def serviceIntegration() {
    Map<String, String> serviceIntegrationMap = new HashMap()
    def mySplit = { data ->
        return Arrays.asList(data.split(",\\s*"))
    }
    // 研发平台（IDE 相关）
    String developmentPlatformStrList = ""
    List<String> developmentPlatform = new ArrayList<>(mySplit(developmentPlatformStrList))
    // 配套服务（中心化、非中心化）
    String supportServiceStrList = "roc, octopus"
    List<String> supportService = new ArrayList<>(mySplit(supportServiceStrList))
    // 运行时（KUN、shark）
    String runtimeStrList = ""
    List<String> runtime = new ArrayList<>(mySplit(runtimeStrList))
    // 业务独立(掌银、GPOS...)
    String businessStrList = ""
    List<String> business = new ArrayList<>(mySplit(businessStrList))
    serviceIntegrationMap.put("developmentPlatform", developmentPlatform)
    serviceIntegrationMap.put("supportService", supportService)
    serviceIntegrationMap.put("runtime", runtime)
    serviceIntegrationMap.put("business", business)
    return serviceIntegrationMap
}

// 根据当前构建服务名，获取集成服务 key 的集合
def getServiceIntegrationNames(serviceName) {
    List<String> serviceIntegrationNameList = new ArrayList()
    Map<String, List> serviceIntegrationMap = serviceIntegration()
    for (Map.Entry entry : serviceIntegrationMap.entrySet()) {
        String mapKey = (String) entry.getKey()
        List<String> mapValue = serviceIntegrationMap.get(mapKey)
        boolean checkServiceName = mapValue.contains(serviceName)
        if (checkServiceName) {
            serviceIntegrationNameList.add(mapKey)
        }
    }
    return serviceIntegrationNameList
}

def urlString2List(str) {
    String url = str.substring(1, str.length()-1)
    List<String> urlList = Arrays.asList(url)
    return urlList
}

def string2Map(str) {
    str = str.substring(1, str.length()-1)
    String[] strs = str.split(",")
    Map<String, String> map = new HashMap<String, String>()
    for (String string : strs) {
        String key = string.split("=")[0]
        String value = string.split("=")[1]
        // 去掉头部空格
        String key1 = key.trim()
        String value1 = value.trim()
        map.put(key1, value1)
    }
    return map
}

// 使用 JsonSlurper 解析 JSON 字符串
def parseJsonToListMap(String json) {
    if (json == null || json.trim() == "") {
        return []
    }
    return new groovy.json.JsonSlurper().parseText(json)
}

def getExecutableJobs(appCodeNameList, buildEnvParam, deployRegion, serverArrayParams) {
    // 研发服务与测试 View 映射对象
    Map<String, String> devTestServerMap = serviceViewMap()
    // 研发服务与测试 Job 名映射对象
    Map<String, String> devTestJobMap = serviceJobMap(buildEnvParam, deployRegion)
    List<Map<String, String>> executableJobs = new ArrayList()
    for (String i : appCodeNameList) {
        boolean checkServerArray = serverArrayParams.contains(i)
        if (!checkServerArray) {
            error "The appCode【${i}】isn't exist. Stopping the build."
        }
        testServerName = devTestServerMap.get(i)
        testJobName = devTestJobMap.get(i)
        path = "/view/${testServerName}/job/${testJobName}/build"
        url = "http://${host}${path}"
        Map<String, String> executableJobMap = new HashMap()
        executableJobMap.put("${testJobName}", url)

        echo "executableJobMap : ${executableJobMap}"
        executableJobs.add(executableJobMap)

        echo "appCodeNameList : ${appCodeNameList}"
        echo "buildEnvParam : ${buildEnvParam}"
        echo "serverArrayParams : ${serverArrayParams}"
        echo "executableJobs : ${executableJobs}"
    }
    return executableJobs
}

/* 2025.03.08
 * 新增 kun 发布后，获取业务测试任务分发 Job 地址
 * 一经发布，指定环境 + 多区域 执行
 */
def kunExecutableJobs(env, region, kunAppName) {
    Map<String, String> kunServiceJobMapKeyResp = serviceJobMap(env, region)
    String kunServiceJobMapKey = kunServiceJobMapKeyResp.get(kunAppName)
    Map<String, String> kunServiceJobMapViewResp = serviceViewMap()
    String kunServiceJobMapView = kunServiceJobMapViewResp.get(kunAppName)
    echo "kunServiceJobMapKey : ${kunServiceJobMapKey}"
    path = "/view/${kunServiceJobMapView}/job/${kunServiceJobMapKey}/build"
    url = "http://${host}${path}"
    echo "url: " + url
    return url
}

// 远程构建 autotest Jenkins 上的 job
def remoteBuildAutoTestJob(url, testJobName) {
    def command = "curl -s -X GET -H 'Authorization: Basic ${env.authorization2Base64}' '${url}?token=${env.remoteTestJobToken}'"
    try {
        def exitCode = sh(returnStatus: true, script: command)
        def stdout = sh(returnStdout: true, script: command).trim()
        
        env.EXIT_CODE = exitCode.toString()
        echo "执行命令: ${command}"
        echo "输出内容: ${stdout}"
        echo "退出码: ${exitCode}"

        // 仅在退出码非零或包含错误信息时报错
        if (exitCode != 0 || stdout.contains("404") || stdout.contains("403")) {
            error "Job 【${testJobName}】 触发失败，退出码: ${exitCode}, 错误信息: ${stdout}"
        } else {
            echo "Job 【${testJobName}】 触发成功"
        }
    } catch (Exception e) {
        def exitCode = env.EXIT_CODE ?: "未知"
        error "Job 【${testJobName}】 执行异常: ${e.getMessage()}, 退出码: ${exitCode}"
    }
}

def paramsIsEmpty(data) {
    String dataTmp = data.replaceAll("\\s", "")
    if (dataTmp == null || dataTmp.isEmpty() || dataTmp == "null") {
        return false
    }
    return true
}

def kunExecuteJobs(env, region, appCodeName) {
    echo "Executing kunExecuteJobs method with region: ${region}"
    echo "Executing kunExecuteJobs method with env: ${env}"
    remoteBuildAutoTestJob(kunExecutableJobs(env, region, appCodeName), "${env}-${region}")
}

def executeJobs(executableJobs) {
    echo "Executing executeJobs method with executableJobs: ${executableJobs}"
    for (HashMap jobMap : executableJobs) { 
        echo "jobMap : ${jobMap}"
        if (jobMap instanceof Map) {
            echo "Processing jobMap: ${jobMap}"
            for (Map.Entry<String, String> entry : jobMap.entrySet()) {
                String currentJobKey = entry.getKey()
                String currentJobValue = entry.getValue()
                echo "Calling remoteBuildAutoTestJob with key: ${currentJobKey}, value: ${currentJobValue}"
                remoteBuildAutoTestJob(currentJobValue, currentJobKey)
                sleep time: 200, unit: 'SECONDS'
            }
        } else {
            error "Expected a Map but got ${jobMap.class.name}: ${jobMap}"
        }
    }
}

def stringToList(String input) {
    def trimmed = input.replace("[", "").replace("]", "")
    def parts = trimmed.split(",")
    def result = []
    for (part in parts) {
        def trimmedPart = part.trim()
        if (trimmedPart) {
            result.add(trimmedPart)
        }
    }
    return result
}

// 手动序列化 executableJobs
def serializeExecutableJobs(executableJobs) {
    def result = []
    for (jobMap in executableJobs) {
        def mapStr = []
        for (entry in jobMap.entrySet()) {
            mapStr.add("\"${entry.key}\":\"${entry.value}\"")
        }
        result.add("{${mapStr.join(',')}}")
    }
    return "[${result.join(',')}]"
}


pipeline {
    agent any

    parameters {
        string(
                name: 'APP_CODE',
                description: '研发服务名',
                defaultValue: 'other1'
        )
        choice(
                name: 'RUN_TIME',
                choices: ['dev', 'test', 'uat', 'pre', 'onl', 'kun-sandbox', 'kun-onl'],
                description: '当前构建环境'
        )
        string(
                name: 'REGION',
                defaultValue: 'cn1',
                description: '当前构建区域（支持多区域逗号分隔）'
        )
    }

    environment {
        appCodeName = "${params.APP_CODE}"
        buildEnv = "-${params.RUN_TIME}"
        // isKun = "${params.isKun}"
        deployRegions = params.REGION.split(/\s*,\s*/)
        host = "autotest.uat.sunmi.com"
        remoteTestJobToken = "remoteAutoTest"
    }

    stages {
        // 初始化
        stage('Init') {
            steps {
                withCredentials([
                        string(variable: 'remoteAutoTestName', credentialsId: 'remoteAutoTestName'),
                        string(variable: 'remoteAutoTestUserToken', credentialsId: 'remoteAutoTestUserToken')
                ]) {
                    script {
                        username = "${env.remoteAutoTestName}"
                        userToken = "${env.remoteAutoTestUserToken}"
                        env.authorization2Base64 = Base64.getEncoder().encodeToString("${username}:${userToken}".getBytes())
                    }
                }
                script {
                    echo "APP_CODE 参数接收 : ${env.appCodeName}"
                    echo "RUN_TIME 参数接收 : ${env.buildEnv.substring(1)}"
                    // echo "isKun 参数接收 : ${env.isKun}"
                    echo "deployRegions 接受参数 : ${env.deployRegions}"

                    // 判断 appCodeName 是否存在
                    String currentAppCodeName = env.appCodeName
                    List<String> currentAppCodeNameList = new ArrayList()
                    if (currentAppCodeName.contains(",")) {
                        currentAppCodeNameList = Arrays.asList(currentAppCodeName.split(","))
                    } else {
                        currentAppCodeNameList.add(currentAppCodeName)
                    }
                    echo "currentAppCodeNameList : ${currentAppCodeNameList}"

                    List<Map> executableJobs = new ArrayList()
                    def kunEnv = ["kun-sandbox", "kun-onl"]
                    List<String> currentDeployRegions = stringToList(env.deployRegions)
                    if (!kunEnv.contains(env.buildEnv.substring(1))) {
                        for (String currentDeployRegion : currentDeployRegions) {
                            def jobsForRegion = getExecutableJobs(currentAppCodeNameList, buildEnv, currentDeployRegion.toUpperCase(), serverArray)
                            executableJobs.addAll(jobsForRegion)
                        }
                    }
                    env.executableJobs = serializeExecutableJobs(executableJobs)
                    // env.executableJobs = new JsonBuilder(executableJobs).toJson()
                    echo "env.executableJobs : ${env.executableJobs}"
                }
            }
        }

        stage('baseRegressionTest') {
            when {
                expression {
                    // 新增KUN CICD执行策略
                    /**
                    两个应用：kun、kun-sandbox 
                    部署环境只消费：pre、onl
                    kun-sandbox pre{CN} : 执行基线用例
                    kun-sandbox onl{CN} : 执行基线用例
                    kun-sandbox onl{其他区域} : 执行基线用例 + 对应环境业务pre用例

                    kun pre{CN} : 执行基线用例
                    kun onl{CN} : 执行基线用例
                    kun onl{其他区域} : 执行基线用例 + 对应环境业务onl用例
                    **/
                    def notAllowedEnvs = ["-dev", "-kun-sandbox", "-kun-onl"]
                    def thirdPartyAppList = ["octopus", "roc", "payment", "Backend-max-amoeba", "kun", "kun-sandbox"]
                    def isKunApp = ["kun", "kun-sandbox"]

                    if (isKunApp.contains(env.appCodeName)) {
                        if (!["pre", "onl"].contains(env.buildEnv.substring(1))) {
                            return false
                        }
                    }
                    return !notAllowedEnvs.contains(env.buildEnv) && thirdPartyAppList.contains(env.appCodeName) 
                }
            }
            steps {
                script {
                    List<String> currentDeployRegions = stringToList(env.deployRegions)
                    int currentDeployRegionsSize = currentDeployRegions.size()
                    int sleepTime = 200
                    // 暂时间隔3分钟，后面再看能不能动态处理
                    if (currentDeployRegionsSize > 1) {
                        sleepTime = 200
                    } 
                    String viewValue = "MAX"
                    // if (["kun", "kun-sandbox"].contains(env.appCodeName)) {
                    //     viewValue = "KUN"
                    // }

                    currentDeployRegions.each { region ->
                        String deployRegion = region.toUpperCase()
                        String baseRegressionTestJob = "max${deployRegion}-base-scenario${buildEnv}"
                        String baseRegressionTestUrl = "http://autotest.uat.sunmi.com/view/${viewValue}/job/${baseRegressionTestJob}/build"
                        remoteBuildAutoTestJob(baseRegressionTestUrl, baseRegressionTestJob)
                        sleep time: sleepTime, unit: 'SECONDS'
                    }
                }
            }
        }

        stage('KUN-CICD') {
            when {
                expression {
                    List<String> dRs = stringToList(env.deployRegions)
                    ["kun", "kun-sandbox"].contains(env.appCodeName) && 
                    ["-pre", "-onl"].contains(env.buildEnv) && 
                    !dRs.contains("cn1")
                    // "kun".equals(env.appCodeName)
                    // ["kun-sandbox", "kun-onl"].contains(env.buildEnv.substring(1))
                }
            }
            steps {
                script {
                    echo "KUN-CICD Start"
                    stringToList(env.deployRegions).each { region ->
                        kunExecuteJobs(env.buildEnv, region, env.appCodeName)
                    }
                }
            }
        }

        stage('Colud-CICD') {
            when {
                expression {
                    !["dev", "uat", "kun-sandbox", "kun-onl"].contains(env.buildEnv.substring(1)) && 
                    !["kun", "kun-sandbox"].contains(env.appCodeName)
                }
            }
            steps {
                script {
                    echo "Colud-CICD Start"
                    echo "env.executableJobs : ${env.executableJobs}"
                    /**
                    踩坑记录:
                    new JsonSlurper().parseText()返回是LazyMap对象，无法序列化。并且循环方式不支持增强型。
                    导致executeJobs函数执行时循环失败。
                    需要转成HashMap即可
                    **/ 
                    def executableJobs2Array = new JsonSlurper().parseText(env.executableJobs).collect { new HashMap(it) }
                    executeJobs(executableJobs2Array)
                }
            }
        }
    }
    post {
        always {
            script {
                def noRunEnv = ["-dev", "-uat"]
                if (noRunEnv.contains(env.buildEnv)) {
                    echo "Current buildEnv: ${env.buildEnv}, 非 CI 环境"
                }
            }
        }
    }
}